package org.jaronsource.framework.core.dao.support;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.persistence.Query;

import org.jaronsource.framework.core.dao.support.Criteria.WhereEntry;
import org.jaronsource.framework.util.StringUtils;

public class DaoUtils {

	public static void processFetchCount(	Criteria criteria,
											StringBuilder whereSqlBuilder ) {

		List<Fetch> fetches = criteria.getFetchList();

		for ( Fetch fetch : fetches ) {
			Fetch.JoinType joinType = fetch.getJoinType();
			if ( Fetch.JoinType.JOINTYPE_INNER.equals( joinType ) || Fetch.JoinType.JOINTYPE_INNER_FETCH.equals( joinType ) ) whereSqlBuilder.append( String.format( " INNER JOIN o.%s", fetch.getTargetObjectName() ) );
			else if ( Fetch.JoinType.JOINTYPE_LEFT.equals( joinType ) || Fetch.JoinType.JOINTYPE_LEFT_FETCH.equals( joinType ) ) whereSqlBuilder.append( String.format( " LEFT JOIN o.%s", fetch.getTargetObjectName() ) );
			else if ( Fetch.JoinType.JOINTYPE_RIGHT.equals( joinType ) || Fetch.JoinType.JOINTYPE_RIGHT_FETCH.equals( joinType ) ) whereSqlBuilder.append( String.format( " RIGHT JOIN o.%s", fetch.getTargetObjectName() ) );
			else whereSqlBuilder.append( String.format( " LEFT JOIN o.%s", fetch.getTargetObjectName() ) );
		}

	}

	public static void processFetch(	Criteria criteria,
										StringBuilder whereSqlBuilder ) {

		List<Fetch> fetches = criteria.getFetchList();

		for ( Fetch fetch : fetches ) {
			Fetch.JoinType joinType = fetch.getJoinType();
			if ( Fetch.JoinType.JOINTYPE_INNER.equals( joinType ) ) whereSqlBuilder.append( String.format( " INNER JOIN o.%s", fetch.getTargetObjectName() ) );
			else if ( Fetch.JoinType.JOINTYPE_INNER_FETCH.equals( joinType ) ) whereSqlBuilder.append( String.format( " INNER JOIN FETCH o.%s", fetch.getTargetObjectName() ) );
			else if ( Fetch.JoinType.JOINTYPE_LEFT.equals( joinType ) ) whereSqlBuilder.append( String.format( " LEFT JOIN o.%s", fetch.getTargetObjectName() ) );
			else if ( Fetch.JoinType.JOINTYPE_LEFT_FETCH.equals( joinType ) ) whereSqlBuilder.append( String.format( " LEFT JOIN FETCH o.%s", fetch.getTargetObjectName() ) );
			else if ( Fetch.JoinType.JOINTYPE_RIGHT.equals( joinType ) ) whereSqlBuilder.append( String.format( " RIGHT JOIN o.%s", fetch.getTargetObjectName() ) );
			else if ( Fetch.JoinType.JOINTYPE_RIGHT_FETCH.equals( joinType ) ) whereSqlBuilder.append( String.format( " RIGHT JOIN FETCH o.%s", fetch.getTargetObjectName() ) );
			else whereSqlBuilder.append( String.format( " LEFT JOIN o.%s", fetch.getTargetObjectName() ) );
		}

	}

	public static void processWhere(	Criteria criteria,
										StringBuilder whereSqlBuilder,
										Map<String, Object> parameterMap ) {

		List<Criteria.ParamEntry> entries = criteria.getEntries();
		whereSqlBuilder.append( " WHERE 1=1" );

		for ( Iterator<Criteria.ParamEntry> iteratorParams = entries.iterator(); iteratorParams.hasNext(); ) {
			Criteria.ParamEntry entry = iteratorParams.next();

			if ( entry.getValue() == null ) {// 如果参数是NULL
				processWhereNullValue( whereSqlBuilder, entry );
			}
			else {
				processWhereGeneralValue( whereSqlBuilder, parameterMap, entry );
			}
		}

		List<WhereEntry> whereEntries = criteria.getWhereEntries();
		if ( whereEntries != null && !whereEntries.isEmpty() ) {
			Pattern p = Pattern.compile( "(\\?)" );
			int index = 0;
			for ( WhereEntry whereEntry : whereEntries ) {
				List<Object> whereParams = whereEntry.getWhereParams();
				String whereClause = whereEntry.getWhereClause();
				if ( whereParams == null || whereParams.isEmpty() ) {
					whereSqlBuilder.append( " AND (" + whereClause + ")" );
				}
				else {
					Matcher m = p.matcher( whereClause );

					StringBuffer sb = new StringBuffer( 100 );
					while ( m.find() ) {
						m.appendReplacement( sb, ":__param__" + index );
						parameterMap.put( "__param__" + index, whereParams.get( index ) );
						index++;
					}
					m.appendTail( sb );
					whereSqlBuilder.append( " AND (" + sb.toString() + ")" );
				}
			}
		}

	}

	public static void processWhereGeneralValue(	StringBuilder whereSqlBuilder,
													Map<String, Object> parameterMap,
													Criteria.ParamEntry entry ) {
		whereSqlBuilder.append( " AND" );
		String fieldName = entry.getParamName();
		String paramName = StringUtils.generateString();

		String queryCase = entry.getQueryCase();
		Object value = entry.getValue();
		whereSqlBuilder.append( " o." + fieldName );
		whereSqlBuilder.append( " " + queryCase );
		whereSqlBuilder.append( " :" + paramName );
		parameterMap.put( paramName, value );
	}

	private static void processWhereNullValue(	StringBuilder whereSqlBuilder,
												Criteria.ParamEntry entry ) {
		whereSqlBuilder.append( " AND" );
		whereSqlBuilder.append( ' ' ).append( entry.getParamName() ).append( " IS NULL " );
	}

	public static void processSort( Sort sort, StringBuilder sortBuilder ) {
		if ( sort != null ) {
			Boolean orderByPresent = Boolean.FALSE;
			for ( Sort.OrderEntry orderEntry : sort ) {
				sortBuilder.append( orderByPresent ? "," : " ORDER BY" );
				sortBuilder.append( " o." + orderEntry.getOrderBy() );
				sortBuilder.append( " " + orderEntry.getOrder() );
				orderByPresent = Boolean.TRUE;
			}
		}
		// else {
		// sortBuilder.append( " ORDER BY 1" );
		// }

	}

	public static void setQueryParam( Query query, Object[] params ) {
		int position = 1;
		for ( Object param : params ) {
			query.setParameter( position++, param );
		}
	}

	public static void setQueryParam( Query query, Map<String, ?> parameterMap ) {
		for ( Iterator<String> iterator = parameterMap.keySet().iterator(); iterator.hasNext(); ) {
			String key = iterator.next();
			Object value = parameterMap.get( key );
			query.setParameter( key, value );
		}
	}

}
